
Imports System
Imports System.Collections
Imports System.Data
Imports System.Data.SqlClient
Imports _2bMatesSite.Common


Namespace _2bMatesSite.BO
	''' <summary>
	''' 2BMates messages.
	''' </summary>
	Public Class Message
		Inherits BaseMessage
		Protected messageID As Integer = -1
		Protected rcptList As New ArrayList()
		Protected box As Messages.BoxType = Messages.BoxType.btOutbox

		Public Sub New(ByVal dr As SqlDataReader)
			Init(dr)
		End Sub

		Public Sub New(ByVal fromUID As Integer, ByVal toUID As Integer, ByVal subject As String, ByVal body As String)
			senderUID = fromUID
			Me.subject = subject
			Me.body = body

			rcptList.Add(toUID)
		End Sub

		Public Overloads Overrides ReadOnly Property ID() As Integer
			Get
				Return messageID
			End Get
		End Property

		Public Overridable ReadOnly Property StoreInOutbox() As Boolean
			Get
				Return True
			End Get
		End Property

		Public Overridable ReadOnly Property MessageType() As Messages.MessageType
			Get
				Return Messages.MessageType.mtMail
			End Get
		End Property

		Public Overridable ReadOnly Property Recipients() As ArrayList
			Get
				Return New ArrayList(rcptList)
			End Get
		End Property

		Public Overridable Sub RemoveRecipient(ByVal userID As Integer)
			If messageID >= 0 Then
				Throw New MessageException("Can't remove recipients from an already sent message.")
			End If
			rcptList.Remove(userID)
		End Sub

		Public Overridable Sub AddRecipient(ByVal userID As Integer)
			If messageID >= 0 Then
				Throw New MessageException("Can't add recipients to an already sent message.")
			End If
			rcptList.Add(userID)
		End Sub

		Public ReadOnly Property Box() As Messages.BoxType
			Get
				Return box
			End Get
		End Property

		Public Overloads Overrides Sub Send()
			If messageID >= 0 Then
				Throw New MessageException("Can't send messages that are already sent.")
			End If

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Dim trans As SqlTransaction = conn.BeginTransaction()

			Try
				Send(trans, MessageType)
				trans.Commit()
			Catch generatedExceptionName As Exception
				trans.Rollback()
				Throw
			Finally
				conn.Close()
			End Try
		End Sub

		Public Overloads Overrides Sub Save()
			If messageID < 0 Then
				Throw New MessageException("Can't update messages that are not yet sent.")
			End If
			Update()
		End Sub

		Public Overloads Overrides Sub Delete()
			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()

			Try
				Dim cmd As New SqlCommand("DELETE FROM Messages WHERE ID=@ID")
				cmd.Connection = conn
				cmd.Parameters.Add("@ID", messageID)
				cmd.ExecuteNonQuery()

				messageID = -1
			Finally
				conn.Close()
			End Try
		End Sub

		Public Sub SendWelcome()
			SentMessageType(Messages.MessageType.mtWelcome)
		End Sub

		Public Sub SendGroupMessage()
			SentMessageType(Messages.MessageType.mtGroupMessage)
		End Sub

		Protected Sub SentMessageType(ByVal msgType As Messages.MessageType)
			If messageID >= 0 Then
				Throw New MessageException("Can't send messages that are already sent.")
			End If

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Dim trans As SqlTransaction = conn.BeginTransaction()

			Try
				Send(trans, msgType)
				trans.Commit()
			Catch generatedExceptionName As Exception
				trans.Rollback()
				Throw
			Finally
				conn.Close()
			End Try
		End Sub

		'
		' Private functions
		'

		Protected Overridable Sub Init(ByVal dr As SqlDataReader)
			messageID = dr.GetInt32(dr.GetOrdinal("ID"))

			subject = DBManager.GetNZString(dr, "Subject")

			body = DBManager.GetNZString(dr, "Body")

			senderUID = dr.GetInt32(dr.GetOrdinal("FromUID"))

			Dim ToUID As Integer = DBManager.GetNZInt32(dr, "ToUID")
			If ToUID > 0 Then
				rcptList.Add(ToUID)
			End If

			messageRead = dr.GetBoolean(dr.GetOrdinal("StatusRead"))
			messageDeleted = dr.GetBoolean(dr.GetOrdinal("StatusDeleted"))

			dateSent = dr.GetDateTime(dr.GetOrdinal("Date"))

			box = DirectCast(dr.GetInt32(dr.GetOrdinal("Box")), Messages.BoxType)
		End Sub


		Protected Function Insert(ByVal rcpt As Integer, ByVal [date] As DateTime, ByVal box As Messages.BoxType) As Integer
			Dim msgID As Integer = -1

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Dim trans As SqlTransaction = conn.BeginTransaction()

			Try
				msgID = Insert(trans, rcpt, [date], box)
				trans.Commit()
			Catch generatedExceptionName As Exception
				trans.Rollback()
			Finally
				conn.Close()
			End Try

			Return msgID
		End Function

		Protected Function Insert(ByVal trans As SqlTransaction, ByVal rcpt As Integer, ByVal [date] As DateTime, ByVal box As Messages.BoxType) As Integer
			Dim conn As SqlConnection = trans.Connection

			Dim cmd As New SqlCommand("SaveMessage")
			cmd.CommandType = CommandType.StoredProcedure
			cmd.Connection = conn
			cmd.Transaction = trans

			PopulateCommand(cmd)

			cmd.Parameters.Add("@FromUID", senderUID)
			DBManager.SetNZValue(cmd, "@ToUID", rcpt)

			cmd.Parameters.Add("@Date", [date])
			cmd.Parameters.Add("@Box", DirectCast(box, Integer))

			Dim paramID As SqlParameter = cmd.Parameters.Add("@ID", SqlDbType.Int)
			paramID.Direction = ParameterDirection.Output

			cmd.ExecuteNonQuery()

			Return DirectCast(paramID.Value, Integer)
		End Function

		Protected Sub Send(ByVal trans As SqlTransaction, ByVal msgType As Messages.MessageType)
			Dim [date] As DateTime = DateTime.Now
			Dim storeInOutBox As Boolean = StoreInOutbox

			Dim sender As User = Me.Sender

			' Chache a hash
			' of all the blockers of the sender
			Dim blockingUsers As UsersBlocked = sender.BlockingUsers
			Dim blockingUsersIDs As New Hashtable()
			For Each usr As User In blockingUsers
				blockingUsersIDs(usr.ID) = usr.ID
			Next

			' NOTE : it is important to call the virutal property
			' instead the member variable directly, so that
			' descendatns may stand inbetween (e.g. BulletinMessage)
			For Each rcpt As Integer In Recipients
				If blockingUsersIDs.Contains(rcpt) Then
					Continue For
					' Skip a blocking user
				End If

				' Send one to the recipient's inbox
				Dim msgID As Integer = Insert(trans, rcpt, [date], Messages.BoxType.btInbox)

				If msgType <> Messages.MessageType.mtWelcome Then
					' Send the receiver a notification
					Users.SendMailNotification(Users.GetUserByID(rcpt), sender, msgID, msgType)
				End If

				If storeInOutBox Then
					Insert(trans, rcpt, [date], Messages.BoxType.btOutbox)
					' Store one in the sender's outbox
				End If
			Next
		End Sub

		Protected Overridable Sub Update()
			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()

			Try
				Dim cmd As New SqlCommand(GetUpdateSQL())
				cmd.Connection = conn

				PopulateCommand(cmd)
				cmd.Parameters.Add("@ID", messageID)

				cmd.ExecuteNonQuery()
			Finally
				conn.Close()
			End Try
		End Sub

		Protected Overridable Function GetUpdateSQL() As String
			Dim sql As String = "UPDATE Messages" + Environment.NewLine
			sql += "SET" + Environment.NewLine
			sql += "" & Chr(9) & "Subject = @Subject," + Environment.NewLine
			sql += "" & Chr(9) & "Body = @Body," + Environment.NewLine
			sql += "" & Chr(9) & "StatusRead = @StatusRead," + Environment.NewLine
			sql += "" & Chr(9) & "StatusDeleted = @StatusDeleted," + Environment.NewLine
			sql += "" & Chr(9) & "MessageType = @MessageType" + Environment.NewLine
			sql += "WHERE" + Environment.NewLine
			sql += "" & Chr(9) & "ID = @ID" + Environment.NewLine

			Return sql
		End Function

		'	NOTE : the following params are not set
		'	@ID
		'	@FromUID
		'	@ToUID
		'	@Date
		'	@Box
		Protected Overridable Sub PopulateCommand(ByVal cmd As SqlCommand)
			cmd.Parameters.Add("@Subject", subject)
			cmd.Parameters.Add("@Body", body)
			cmd.Parameters.Add("@StatusRead", messageRead)
			cmd.Parameters.Add("@StatusDeleted", messageDeleted)
			cmd.Parameters.Add("@MessageType", DirectCast(MessageType, Integer))
		End Sub
	End Class
End Namespace






